package com.sqlcheck.service.impl;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sqlcheck.config.GitLabConfig;
import com.sqlcheck.dto.git.GitProjectInfo;
import com.sqlcheck.dto.git.GitRepositoryInfo;
import com.sqlcheck.service.GitLabApiService;
import com.sqlcheck.enums.GitPlatform;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
@Service
@RequiredArgsConstructor
public class GitLabApiServiceImpl implements GitLabApiService {
    
    private final GitLabConfig gitLabConfig;
    private final RestTemplate restTemplate;
    private final ObjectMapper objectMapper;
    
    // GitLab项目URL的正则表达式
    private static final Pattern PROJECT_URL_PATTERN = Pattern.compile(
            "https?://([^/]+)/([^/]+/[^/]+)(?:\\.git)?/?$"
    );
    
    @Override
    public GitPlatform getSupportedPlatform() {
        return GitPlatform.GITLAB;
    }
    
    @Override
    public List<GitProjectInfo> getUserProjects(String accessToken, int page, int perPage) {
        try {
            String apiUrl = String.format("%s/api/v4/projects?membership=true&page=%d&per_page=%d&order_by=last_activity_at&sort=desc",
                    gitLabConfig.getServerUrl(), page, perPage);
            
            HttpHeaders headers = new HttpHeaders();
            headers.setBearerAuth(accessToken);
            HttpEntity<Void> request = new HttpEntity<>(headers);
            
            ResponseEntity<String> response = restTemplate.exchange(apiUrl, HttpMethod.GET, request, String.class);
            
            if (response.getStatusCode().is2xxSuccessful() && response.getBody() != null) {
                JsonNode jsonArray = objectMapper.readTree(response.getBody());
                List<GitProjectInfo> projects = new ArrayList<>();
                
                for (JsonNode projectNode : jsonArray) {
                    projects.add(parseProjectInfo(projectNode));
                }
                
                return projects;
            }
            
            log.error("获取用户项目列表失败: {}", response.getStatusCode());
            return new ArrayList<>();
            
        } catch (Exception e) {
            log.error("获取用户项目列表异常: {}", e.getMessage(), e);
            return new ArrayList<>();
        }
    }
    
    @Override
    public GitProjectInfo getProjectByUrl(String accessToken, String projectUrl) {
        try {
            // 解析项目URL获取项目路径
            String projectPath = extractProjectPath(projectUrl);
            if (projectPath == null) {
                log.error("无效的GitLab项目URL: {}", projectUrl);
                return null;
            }
            
            // URL编码项目路径
            String encodedPath = URLEncoder.encode(projectPath, StandardCharsets.UTF_8);
            String apiUrl = String.format("%s/api/v4/projects/%s", gitLabConfig.getServerUrl(), encodedPath);
            
            HttpHeaders headers = new HttpHeaders();
            headers.setBearerAuth(accessToken);
            HttpEntity<Void> request = new HttpEntity<>(headers);
            
            ResponseEntity<String> response = restTemplate.exchange(apiUrl, HttpMethod.GET, request, String.class);
            
            if (response.getStatusCode().is2xxSuccessful() && response.getBody() != null) {
                JsonNode projectNode = objectMapper.readTree(response.getBody());
                return parseProjectInfo(projectNode);
            }
            
            log.error("获取项目信息失败: {} - {}", response.getStatusCode(), response.getBody());
            return null;
            
        } catch (Exception e) {
            log.error("获取项目信息异常: {}", e.getMessage(), e);
            return null;
        }
    }
    
    @Override
    public GitRepositoryInfo getRepositoryInfo(String accessToken, Long projectId) {
        try {
            String apiUrl = String.format("%s/api/v4/projects/%d/repository", gitLabConfig.getServerUrl(), projectId);
            
            HttpHeaders headers = new HttpHeaders();
            headers.setBearerAuth(accessToken);
            HttpEntity<Void> request = new HttpEntity<>(headers);
            
            ResponseEntity<String> response = restTemplate.exchange(apiUrl, HttpMethod.GET, request, String.class);
            
            if (response.getStatusCode().is2xxSuccessful() && response.getBody() != null) {
                JsonNode repoNode = objectMapper.readTree(response.getBody());
                
                // 获取最后一次提交信息
                JsonNode lastCommit = getLastCommit(accessToken, projectId);
                
                return GitRepositoryInfo.builder()
                        .id(projectId)
                        .defaultBranch(repoNode.has("default_branch") ? repoNode.get("default_branch").asText() : "main")
                        .emptyRepo(repoNode.has("empty_repo") ? repoNode.get("empty_repo").asBoolean() : false)
                        .lastCommitId(lastCommit != null && lastCommit.has("id") ? lastCommit.get("id").asText() : null)
                        .lastCommitMessage(lastCommit != null && lastCommit.has("message") ? lastCommit.get("message").asText() : null)
                        .lastCommitAuthor(lastCommit != null && lastCommit.has("author_name") ? lastCommit.get("author_name").asText() : null)
                        .lastCommitDate(lastCommit != null && lastCommit.has("created_at") ? lastCommit.get("created_at").asText() : null)
                        .build();
            }
            
            log.error("获取仓库信息失败: {}", response.getStatusCode());
            return null;
            
        } catch (Exception e) {
            log.error("获取仓库信息异常: {}", e.getMessage(), e);
            return null;
        }
    }
    
    @Override
    public GitRepositoryInfo getRepositoryInfo(String accessToken, String projectId) {
        try {
            return getRepositoryInfo(accessToken, Long.parseLong(projectId));
        } catch (NumberFormatException e) {
            log.error("GitLab项目ID格式错误: {}", projectId);
            return null;
        }
    }
    
    @Override
    public boolean validateProjectAccess(String accessToken, String projectUrl) {
        if (accessToken == null || accessToken.trim().isEmpty()) {
            log.warn("访问令牌为空");
            return false;
        }
        if (projectUrl == null || projectUrl.trim().isEmpty()) {
            log.warn("项目URL为空");
            return false;
        }
        
        try {
            GitProjectInfo projectInfo = getProjectByUrl(accessToken, projectUrl);
            return projectInfo != null;
        } catch (Exception e) {
            log.error("验证项目访问权限异常: {}, URL: {}", e.getMessage(), projectUrl);
            return false;
        }
    }
    
    @Override
    public String getDefaultBranch(String accessToken, Long projectId) {
        try {
            String apiUrl = String.format("%s/api/v4/projects/%d", gitLabConfig.getServerUrl(), projectId);
            
            HttpHeaders headers = new HttpHeaders();
            headers.setBearerAuth(accessToken);
            HttpEntity<Void> request = new HttpEntity<>(headers);
            
            ResponseEntity<String> response = restTemplate.exchange(apiUrl, HttpMethod.GET, request, String.class);
            
            if (response.getStatusCode().is2xxSuccessful() && response.getBody() != null) {
                JsonNode projectNode = objectMapper.readTree(response.getBody());
                return projectNode.has("default_branch") ? projectNode.get("default_branch").asText() : "main";
            }
            
            return "main";
            
        } catch (Exception e) {
            log.error("获取默认分支异常: {}", e.getMessage(), e);
            return "main";
        }
    }
    
    @Override
    public String getDefaultBranch(String accessToken, String projectId) {
        try {
            return getDefaultBranch(accessToken, Long.parseLong(projectId));
        } catch (NumberFormatException e) {
            log.error("GitLab项目ID格式错误: {}", projectId);
            return "main";
        }
    }
    
    @Override
    public List<String> getProjectBranches(String accessToken, Long projectId) {
        try {
            String apiUrl = String.format("%s/api/v4/projects/%d/repository/branches", gitLabConfig.getServerUrl(), projectId);
            
            HttpHeaders headers = new HttpHeaders();
            headers.setBearerAuth(accessToken);
            HttpEntity<Void> request = new HttpEntity<>(headers);
            
            ResponseEntity<String> response = restTemplate.exchange(apiUrl, HttpMethod.GET, request, String.class);
            
            if (response.getStatusCode().is2xxSuccessful() && response.getBody() != null) {
                JsonNode branchesArray = objectMapper.readTree(response.getBody());
                List<String> branches = new ArrayList<>();
                
                for (JsonNode branchNode : branchesArray) {
                    if (branchNode.has("name")) {
                        branches.add(branchNode.get("name").asText());
                    }
                }
                
                return branches;
            }
            
            log.error("获取项目分支列表失败: {}", response.getStatusCode());
            return new ArrayList<>();
            
        } catch (Exception e) {
            log.error("获取项目分支列表异常: {}", e.getMessage(), e);
            return new ArrayList<>();
        }
    }
    
    @Override
    public List<String> getProjectBranches(String accessToken, String projectId) {
        try {
            return getProjectBranches(accessToken, Long.parseLong(projectId));
        } catch (NumberFormatException e) {
            log.error("GitLab项目ID格式错误: {}", projectId);
            return new ArrayList<>();
        }
    }
    
    @Override
    public String extractProjectIdentifier(String projectUrl) {
        return extractProjectPath(projectUrl);
    }
    
    @Override
    public String buildCloneUrl(String projectUrl, String accessToken) {
        try {
            if (projectUrl == null || projectUrl.trim().isEmpty()) {
                return null;
            }
            
            // 确保URL不以.git结尾
            String cleanUrl = projectUrl.replaceAll("\\.git$", "");
            
            // 构建带Token的克隆URL
            if (cleanUrl.startsWith("https://")) {
                return cleanUrl.replace("https://", "https://oauth2:" + accessToken + "@") + ".git";
            } else if (cleanUrl.startsWith("http://")) {
                return cleanUrl.replace("http://", "http://oauth2:" + accessToken + "@") + ".git";
            }
            
            return cleanUrl + ".git";
            
        } catch (Exception e) {
            log.error("构建克隆URL失败: {}", e.getMessage(), e);
            return projectUrl;
        }
    }
    
    private String extractProjectPath(String projectUrl) {
        if (projectUrl == null || projectUrl.trim().isEmpty()) {
            log.warn("项目URL为空或null");
            return null;
        }
        
        try {
            Matcher matcher = PROJECT_URL_PATTERN.matcher(projectUrl.trim());
            if (matcher.matches()) {
                return matcher.group(2);
            }
            log.warn("项目URL格式不匹配: {}", projectUrl);
            return null;
        } catch (Exception e) {
            log.error("解析项目URL异常: {}, URL: {}", e.getMessage(), projectUrl);
            return null;
        }
    }
    
    private JsonNode getLastCommit(String accessToken, Long projectId) {
        try {
            String apiUrl = String.format("%s/api/v4/projects/%d/repository/commits?per_page=1", gitLabConfig.getServerUrl(), projectId);
            
            HttpHeaders headers = new HttpHeaders();
            headers.setBearerAuth(accessToken);
            HttpEntity<Void> request = new HttpEntity<>(headers);
            
            ResponseEntity<String> response = restTemplate.exchange(apiUrl, HttpMethod.GET, request, String.class);
            
            if (response.getStatusCode().is2xxSuccessful() && response.getBody() != null) {
                JsonNode commitsArray = objectMapper.readTree(response.getBody());
                if (commitsArray.isArray() && commitsArray.size() > 0) {
                    return commitsArray.get(0);
                }
            }
            
            return null;
            
        } catch (Exception e) {
            log.error("获取最后提交信息异常: {}", e.getMessage(), e);
            return null;
        }
    }
    
    private GitProjectInfo parseProjectInfo(JsonNode projectNode) {
        return GitProjectInfo.builder()
                .id(projectNode.get("id").asLong())
                .name(projectNode.get("name").asText())
                .path(projectNode.get("path").asText())
                .fullPath(projectNode.has("path_with_namespace") ? projectNode.get("path_with_namespace").asText() : null)
                .description(projectNode.has("description") && !projectNode.get("description").isNull() ? projectNode.get("description").asText() : null)
                .webUrl(projectNode.has("web_url") ? projectNode.get("web_url").asText() : null)
                .defaultBranch(projectNode.has("default_branch") ? projectNode.get("default_branch").asText() : "main")
                .archived(projectNode.has("archived") ? projectNode.get("archived").asBoolean() : false)
                .visibility(projectNode.has("visibility") ? projectNode.get("visibility").asText() : null)
                .createdAt(projectNode.has("created_at") ? projectNode.get("created_at").asText() : null)
                .lastActivityAt(projectNode.has("last_activity_at") ? projectNode.get("last_activity_at").asText() : null)
                .build();
    }
}